<?php

/**
 * This class contains basic DB functions.
 *  
 * @package Library
 * @subpackage Db 
 * @category Library files
 */

class Db{
    public $history = array();
    private $link = null;
    private $debug = true;  
    private $conf = array();
    
    /**
     * get
     * Returns an instance of Db class
     *
     * @param array $conf is hash with (host,database, user, password)
     * @access public    
     * @return Db
     */
     static function get($conf = false)
     {
        static $instances = array();
        if (!$conf)
        	return $instances;
        $k = serialize($conf);
        if (!isset($instances[$k])){
            $instances[$k] = new Db();
            $instances[$k]->connect($conf['host'], $conf['name'], $conf['user'], $conf['pass']);
        }
        return $instances[$k];
    }
    
    /**
     * getModel
     * Returns model for database work.
     *
     * @param string $tbl database table
     * @return model
     */
    public static function getModel($tbl)
    {
        return Db_Table::get($tbl);
    }

    /**
     * connect
     * This function serves to connect to the database.
     *
     * @param string $host
     * @param string $db_name
     * @param string $user
     * @param string $pass
     * @return boolean
     */
    public function connect($host, $db_name, $user, $pass)
    {
        $this->conf['host'] = $host;
        $this->conf['db'] = $db_name;
        $this->conf['user'] = $user;
        $_SESSION['sqlHistory'][serialize($this->conf)] = array();
        $this->link = mysqli_connect($host, $user, $pass, $db_name);
        if (!$this->link)
            $this->msg("Unable to connect to db server...", true, false);
        $this->query("USE `{$db_name}`");
        //$this->query("SET NAMES 'utf8'");
        return true;
    }
    
    /**
     * query
     * This function executes a query to the database.
     *
     * @param string $sql
     * @return boolean
     */
    public function query($sql)
    {
    	list($usec, $sec) = explode(' ', microtime());
        $start =  ((float)$usec + (float)$sec);
        
        $res = mysqli_query($this->link, $sql);
        list($usec, $sec) = explode(' ', microtime());
        $finish =  ((float)$usec + (float)$sec);
        if ($this->debug){
            $this->history[] = array("sql" => $sql,'time'=>($finish-$start));
            //$_SESSION['sqlHistory'][serialize($this->conf)][] = $sql;
        }
        if (!$res)
        {
            $this->msg(mysqli_error($this->link));
        }
        return $res;
    }
    
    /**
     * getRows
     * This function returns records according to an SQL query.
     *
     * @param string $sql
     * @param boolean $assoc
     * @param string $keyField
     * @return array
     */
    public function getRows($sql, $assoc = true, $keyField = '')
    {
        $rows = array();
        $assocType = $assoc? MYSQL_ASSOC : MYSQL_NUM;
        $res = $this->query($sql);
        while($row = mysqli_fetch_array($res, $assocType)){
            if ($keyField)
                $rows[$row[$keyField]] = $row;
            else 
                $rows[] = $row;
        }
        return $rows;
    }
    
    /**
     * getRow
     * this function returns a single record according to an SQL query.
     *
     * @param string $sql
     * @param boolean $assoc
     * @return array|hash
     */
    public function getRow($sql, $assoc = true)
    {
        $res = $this->query($sql);
        if (mysqli_num_rows($res) == 0)      
            return false;
        return mysqli_fetch_array($res, $assoc? MYSQL_ASSOC : MYSQL_NUM);
    }
	
    /**
     * getRow
     * this function returns a single record according to an SQL query.
     *
     * @param string $sql
     * @param boolean $assoc
     * @return array|hash
     */
    public function getRowFree($sql, $assoc = true)
    {
		unset($this->link);
		$conf = _cfg('db');
		$this->connect($conf['host'],$conf['name'],$conf['user'],$conf['pass']);
		
        $res = $this->query($sql);
        if (mysqli_num_rows($res) == 0)
            return false;
        $return = mysqli_fetch_array($res, $assoc? MYSQL_ASSOC : MYSQL_NUM);
		mysqli_free_result($res);
		
		unset($this->link);
		$conf = _cfg('db');
		$this->connect($conf['host'],$conf['name'],$conf['user'],$conf['pass']);
		return $return;
    }
    
    /**
     * getField
     * This function returns a single field according to an SQL query.
     *
     * @param string $sql
     * @return string
     */
    public function getField($sql)
    {
        $res = $this->getRow($sql, 0);
        if ($res)
            return $res[0];
        return null;
    }
    
    /**
     * getFields
     * This function returns multiple values for a single field according to an SQL query.
     *
     * @param string $sql
     * @return array
     */
    function getFields($sql, $addZero=true)
    {
        $rows = $this->getRows($sql, false);
        $res = array();
        foreach ($rows as $val)
            $res[] = $val[0];
        if (!$res && $addZero)
            $res[] = 0;
        return $res;
    }
    
    /**
     * getHash
     * This function returns hash for id=>title accordinging to an SQL query.
     *
     * @param string $sql
     * @return array
     */
    public function getHash($sql)
    {
        $rows = $this->getRows($sql, false);
        $res = array();
        foreach ($rows as $r)
            $res[$r[0]] = $r[1];
        return $res;
    }
    
    
    /**
     * msg
     * This function displays a message for debugging.
     *
     * @param string $text
     * @param boolean $die
     * @param boolean $query
     * @return null
     */
    private function msg($text, $die = true, $query = true)
    {
        if (!is_array($text))
            $text = array("msg" => $text);      
        if ($query)
            $text['query'] = $this->history[sizeof($this->history)-1]['sql'];
        foreach (debug_backtrace() as $file)
            $text['trace'][] = $file['line'].' , '.$file['file'];
        $text['trace'] = array_reverse($text['trace']);
        $text['conf'] = $this->conf;                
        echo "<hr><pre>";
        print_r($text);
        echo "<pre><hr>";
        if ($die)
            die();
    }
    
    /**
     * update
     * This function updates records according to the set conditions.
     *
     * @param string $table
     * @param array $data
     * @param array $where
     * @return boolean
     */
    public function update($table, $data, $where)
    {
        $temp = array();
        foreach ($data as $key => $value)
            $temp[] = " $key = " . (substr($value, 0, 1) == '@'? substr($value, 1): "'$value'") . " ";

        $sql = "UPDATE {$table} 
                    SET ".join(',',$temp)."
                    WHERE $where";
        return $this->query($sql);
    }
    
    /**
     * insert
     * This function inserts a single record.
     *
     * @param string $table
     * @param array $data
     * @param boolean $escape
     * @return boolean
     */   
    public function insert($table, $data, $escape = false)
    {   
        $temp = array();
        foreach ($data as $key => $value)
            $temp[] = " $key = " . (substr($value, 0, 1) == '@' && !$escape? substr($value, 1): "'$value'") . " ";

        $sql = "INSERT INTO {$table} 
                    SET ".join(',',$temp)."";
        
        $this->query($sql);
        return $this->getField("SELECT LAST_INSERT_ID()");
    }
    
    /**
     * escape
     * This function escapes the value of the field.
     *
     * @param string $value
     * @return string
     */
    public function escape($value){
        return mysql_real_escape_string($value);
    }
    
    /**
     * date 
     * This function returns date in the given format as string for MySQL
     * 
     * @param int $timestamp datetime as timestamp (current time if omitted)
     * @return string fomratted for mysql datetime
     */
    function date($timestamp = 0) {
        $timestamp = $timestamp ? $timestamp : time();
        return date('Y-m-d H:i:s', $timestamp);
    }
}